#include "preHeader.h"
#include "Session/ClientPacketHandler.h"
#include "Session/CenterSession.h"
#include "Session/SocialServerSession.h"
#include "Session/MapServerMgr.h"
#include "Game/CharacterMgr.h"
#include "Game/Account.h"
#include "GameServer.h"

int ClientPacketHandler::HandleGuildCreate(Account *pAccount, INetPacket &pck)
{
	std::string guildName;
	pck >> guildName;
	GErrorCode err = sCharacterMgr.CheckGuildName(guildName);
	if (err != CommonSuccess) {
		pAccount->SendError(err);
		return SessionHandleSuccess;
	}

	auto pChar = pAccount->GetCharacter();
	auto TryGuildCreate = [=](Coroutine::YieldContext& ctx) -> GErrorCode {
		NetPacket rpcReqPck(G2M_TRY_GUILD_CREATE);
		sMapServerMgr.RPCInvoke2Player(pChar, rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		auto resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		int32 errCode;
		(*resp.pck) >> errCode;
		if (errCode != CommonSuccess) {
			return (GErrorCode)errCode;
		}

		rpcReqPck.Reset(CGX_TRY_GUILD_CREATE);
		rpcReqPck << pChar->guildId << pChar->guid.UID;
		sSocialServerSession.RPCInvoke(rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		(*resp.pck) >> errCode;
		if (errCode != CommonSuccess) {
			return (GErrorCode)errCode;
		}

		rpcReqPck.Reset(CCT_GUILD_CREATE);
		rpcReqPck << pChar->gsId << pChar->guid.UID << guildName;
		sCenterSession.RPCInvoke(rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		std::string_view errMsg;
		(*resp.pck) >> errCode >> errMsg;
		if (errCode != 0) {
			pChar->SendError({CommonTransError, errCode, errMsg});
			return CommonNoWarning;
		}

		uint32 guildId;
		(*resp.pck) >> guildId;

		rpcReqPck.Reset(CGX_GUILD_CREATE);
		rpcReqPck << pChar->gsId << pChar->guildId << pChar->guid.UID
			<< guildId << guildName;
		sSocialServerSession.RPCInvoke(rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		(*resp.pck) >> errCode;
		if (errCode != CommonSuccess) {
			return (GErrorCode)errCode;
		}

		rpcReqPck.Reset(G2M_GUILD_CREATE_RESP);
		sMapServerMgr.RPCInvoke2Player(pChar, rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		(*resp.pck) >> errCode;
		if (errCode != CommonSuccess) {
			return (GErrorCode)errCode;
		}

		NetPacket toClient(SMSG_GUILD_CREATE_RESP);
		toClient << guildId;
		pChar->SendPacket(toClient);

		return CommonSuccess;
	};

	Coroutine::Spawn([=](Coroutine::YieldContext& ctx) {
		auto errCode = TryGuildCreate(ctx);
		if (errCode != CommonSuccess) {
			pChar->SendError(errCode);
		}
	});

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildInvite(Account *pAccount, INetPacket &pck)
{
	uint32 targetId;
	pck >> targetId;

	auto pChar = pAccount->GetCharacter();
	auto pTarget = sCharacterMgr.GetCharacter(targetId);
	if (pTarget == NULL) {
		return TargetNotExist;
	}
	if (!pTarget->isOnline) {
		return TargetOffline;
	}

	NetPacket trans(CGX_GUILD_INVITE);
	trans << pChar->guildId << pChar->guid.UID
		<< pTarget->guildId << pTarget->guid.UID;
	sSocialServerSession.PushSendPacket(trans);

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildInviteResp(Account *pAccount, INetPacket &pck)
{
	uint32 guildId;
	bool isAgree;
	pck >> guildId >> isAgree;
	auto pChar = pAccount->GetCharacter();
	NetPacket trans(CGX_GUILD_INVITE_RESP);
	trans << pChar->guildId << pChar->guid.UID << guildId << isAgree;
	sSocialServerSession.PushSendPacket(trans);
	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildApply(Account *pAccount, INetPacket &pck)
{
	uint32 guildId;
	pck >> guildId;
	auto pChar = pAccount->GetCharacter();
	NetPacket trans(CGX_GUILD_APPLY);
	trans << pChar->guildId << pChar->guid.UID << guildId;
	sSocialServerSession.PushSendPacket(trans);
	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildApplyResp(Account *pAccount, INetPacket &pck)
{
	uint32 applicantId;
	bool isAgree;
	pck >> applicantId >> isAgree;

	auto pChar = pAccount->GetCharacter();
	auto pApplicant = sCharacterMgr.GetCharacter(applicantId);
	if (pApplicant == NULL) {
		return TargetNotExist;
	}

	NetPacket trans(CGX_GUILD_APPLY_RESP);
	trans << pChar->guildId << pChar->guid.UID
		<< pApplicant->guildId << pApplicant->guid.UID << isAgree;
	sSocialServerSession.PushSendPacket(trans);

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildLeave(Account *pAccount, INetPacket &pck)
{
	auto pChar = pAccount->GetCharacter();
	NetPacket trans(CGX_GUILD_LEAVE);
	trans << pChar->guildId << pChar->guid.UID;
	sSocialServerSession.PushSendPacket(trans);
	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildKick(Account *pAccount, INetPacket &pck)
{
	uint32 targetId;
	pck >> targetId;

	auto pChar = pAccount->GetCharacter();
	auto pTarget = sCharacterMgr.GetCharacter(targetId);
	if (pTarget == NULL) {
		return TargetNotExist;
	}

	NetPacket trans(CGX_GUILD_KICK);
	trans << pChar->guildId << pChar->guid.UID
		<< pTarget->guildId << pTarget->guid.UID;
	sSocialServerSession.PushSendPacket(trans);

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildRise(Account *pAccount, INetPacket &pck)
{
	uint32 targetId;
	int8 guildTitle;
	pck >> targetId >> guildTitle;

	auto pChar = pAccount->GetCharacter();
	auto pTarget = sCharacterMgr.GetCharacter(targetId);
	if (pTarget == NULL) {
		return TargetNotExist;
	}

	NetPacket trans(CGX_GUILD_RISE);
	trans << pChar->guildId << pChar->guid.UID
		<< pTarget->guildId << pTarget->guid.UID << guildTitle;
	sSocialServerSession.PushSendPacket(trans);

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildDisband(Account *pAccount, INetPacket &pck)
{
	auto pChar = pAccount->GetCharacter();
	auto TryGuildDisband = [=](Coroutine::YieldContext& ctx) -> GErrorCode {
		NetPacket rpcReqPck(CGX_GUILD_DISBAND);
		rpcReqPck << pChar->guildId << pChar->guid.UID;
		sSocialServerSession.RPCInvoke(rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		auto resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		int32 errCode;
		(*resp.pck) >> errCode;
		if (errCode != CommonSuccess) {
			return (GErrorCode)errCode;
		}

		uint32 guildId;
		(*resp.pck) >> guildId;

		rpcReqPck.Reset(CCT_GUILD_DELETE);
		rpcReqPck << guildId;
		sCenterSession.RPCInvoke(rpcReqPck,
			ctx.GetRPCInvokeCb(), &sGameServer, DEF_S2S_RPC_TIMEOUT);
		resp = ctx.WaitRPCInvokeResp();
		if (resp.err != RPCErrorNone) {
			return CommonInternalError;
		}
		std::string_view errMsg;
		(*resp.pck) >> errCode >> errMsg;
		if (errCode != 0) {
			pChar->SendError({CommonTransError, errCode, errMsg});
			return CommonNoWarning;
		}

		return CommonSuccess;
	};

	Coroutine::Spawn([=](Coroutine::YieldContext& ctx) {
		auto errCode = TryGuildDisband(ctx);
		if (errCode != CommonSuccess) {
			pChar->SendError(errCode);
		}
	});

	return SessionHandleSuccess;
}

int ClientPacketHandler::HandleGuildGetApply(Account *pAccount, INetPacket &pck)
{
	auto pChar = pAccount->GetCharacter();
	NetPacket trans(CGX_GUILD_GET_APPLY);
	trans << pChar->guildId << pChar->guid.UID;
	sSocialServerSession.PushSendPacket(trans);
	return SessionHandleSuccess;
}
